+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Systemprogrammierung in PCQ-Pascal + + Kurs für AMIGAGadget und Purity- Teil I + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Viele kennen Turbo Pascal vom PC. Mit dem PCQ-Compiler von der Fish-Disk 503 steht nun auf dem Amiga ein billiger und leistungsfähiger Pascal- Compiler zur Verfügung. Nun ist der grundsätzliche Iso-Standard implementiert, die Systemprogrammierung stellt aber PC-Programmierer vor ein Rätsel. Deshalb nun - ein Kurs ! (Tusch...) Der kann natürlich auch mit der PCQ Version 1.1 durchgeführt werden, aber hauptsächlich wegen der Includefiles empfiehlt sich Version 1.2. I. Voraussetzungen Um diesem Kurs folgen zu können, sollte man sich mit dem CLI auskennen. Außerdem brauchte man den PCQ-Compiler inklusive dem Assembler A68k und dem BLink. Mit diesen sollte man sich auch auskennen (notfalls im DOC-File von PCQ nachlesen). Als erstes stelle man sich eine bootfähige Pascaldisk zusammen. Der Pcq kommt als "Pascal" in den C-Ordner, wohin ihm der A68k und BLink folgen. Die PCQ.Lib kommt einfach in das Rootdirectory (man könnte auch ein eigenes Libraries-Subdirectory erstellen, aber bei einer Library lohnt sich das kaum...). Desweiteren benötigen wir noch den Include-Ordner und einen ASCII-Editor (es empfiehlt sich der DME). Das war's schon an Voraussetzungen. Nun kann's losgehen. II. Screens und Windows Wie aus der Überschrift erkennbar, soll es unsere erste Aufgabe sein, erstmal einen eigenen Bildschirm zu öffnen. Nun gibt es auf dem Amiga verschiedene Programme, die sich um bestimmte Aufgabenteile kümmern, die sogenannten "Libraries". Bevor man sich an ihren Routinen gütlich tun kann, muß man sie erstmal öffnen. Nun brauchen wir, um einen Screen zu öffnen, natürlich nicht alle Libraries, sondern nur die sogenannten "Intuition.Library". Sie kümmert sich um Fenster, Bildschirme, Menüleisten und Gadgets (da gibt's kein deutsches Wort, das passt...oder ?). Und - wie schön für uns - da der Startupcode von PCQ-Pascal diese Library schon benötigt, brauchen wir sie noch nicht einmal mehr von Hand aufzumachen. Auf alle von ihr zur Verfügung gestellten Routinen können wir in einem PCQ-Programm ohne Umstände zurückgreifen. (Na ja, das wird später noch eingeschränkt.... wartet's ab.) Ein's muß man aber doch tun : das File "Intuition.I" in den Programmcode einbinden. Das geht ganz einfach : mit dem Compilerbefehl ($I "Include:Intuition/Intuition.I" }. Er öffnet ein File, in dem diverse Strukturen zur Verwaltung von Strukturen des Systems enthalten sind. Unser Programm sieht also so aus : Program IntuitionTest (input , output); { Listing für den AMIGAGadget/Purity - Pascalkurs , Grundgerüst } {$I "Include:Intuition/Intuition.I" } BEGIN END. Was macht das Programm ? Antwort : nichts, da der Programmblock leer ist. Allerdings ist es ein Gerüst, in das man beliebige Intuition- operationen einbauen kann. Um einen Bildschirm zu öffnen, muß man die Funktion "OpenScreen" aufrufen. Sie benötigt als Parameter die Addresse einer NewScreen-Struktur, in der die Daten für den zu erstellenden Bildschirm enthalten sind. Der Wert, den sie zurückliefert ist entweder Null (=NIL), wenn der Versuch, den Bildschirm zu öffnen, fehlgeschlagen ist (passiert bei uns nicht !!! Oder MEISTENS nicht...) oder ein Zeiger auf eine Screenstruktur, die die Daten des geöffneten Bildschirms enthält. Wie sieht nun diese NewScreen-Struktur aus ? Antwort : so : NewScreen = record LeftEdge, linke Ecke des Screens (meistens 0) TopEdge, obere Ecke des Screens (meistens 0) Width, Breite des Screens (mstns. 320 o. 640) Height, Höhe des Screens (mstns. 256 o. 512) Depth : Short; Anzahl der Bitplanes (siehe A 1) DetailPen, Registernummer des Zeichenstifts (A 2) BlockPen : Byte; Registernummer des Blockstifts (A 2) ViewModes : Short; legt den sogenannten ViewPort fest (A 3) SType : Short; Art des Screens (A 4) Font : Address; Zeiger auf den Schriftsatz (mstns. Nil) DefaultTitle : String; Zeiger auf den Titel des Screens Gadgets : Address; Zeiger auf Screengadgets (unwichtig) CustomBitMap : Address; Zeiger auf selbstgemachte BitMap (mstns. Nil) end; A 1 : Um die Anzahl der Farben zu bestimmen, muß man sogenannte Bitplanes verwenden. Diese kann man sich in etwa als große rechteckige "Bitflächen" vorstellen. +-------------------+ Um dies zu verstehen, muß man sich | | mit der Art und Weise befassen, in der | | der Amiga seine Grafik darstellt. | | Dies funktioniert, indem jedem Punkt | | des Bildschirms ein Bit pro +-------------------+ Bitplane zugeordnet ist. Ein Bildpunkt kann nun pro Bitplane also zwei Zustände annehmen : Bit gesetzt und Bit nicht gesetzt. Bei einer Bitplane kann es also nur zwei Arten von Bildpunkten geben : 0 (Bit in Bitplane nicht gesetzt) und 1. Was sollen nun diese Zahlen ?? Was bestimmen sie ? Ganz einfach : pro Bildschirm stellt der Amiga eine bestimmte Anzahl von Farben zur Verfügung (nämlich exakt zwei hoch Anzahl der Bitplanes, in unserem Falle 2 hoch 1=2). Diese sind von 0 bis (2^Anzahl)-1 durchnummeriert, bei uns also 0 und 1. Aha !!! Die Bits der Bitplane zeigen also auf das Farbregister, mit dem der entsprechende Bildpunkt eingefärbt wird. Nun legen wir auf diese eine Bitplane noch eine zweite drauf. Betrachtet wir einen Ausschnitt : 1.Bitplane : 001001110010 2.Bitplane : 010000110101 Man sieht, es gibt vier Kombinationsmöglichkeiten : (die erste Zahl ist die höchste Bitplane) 00 , 01 , 10 , 11 - Binärzahlen. Ich gehe mal davon aus, daß jeder mit ihnen umgehen kann. Dezimal geschrieben gibt es also folgende Zuweisungsmöglichkeiten bei 2 Bitplanes : 0 , 1 , 2 , 3. Man ahnt schon, was diese Zahlen bedeuten : sie kennzeichnen das Register (den Farbtopf), aus dem der Amiga die Farbe zur Darstellung des entsprechenden Bildpunktes schöpfen muß. Und zuguterletzt noch die Variante mit 3 Bitplanes : 1.BP : 001001110010 2.BP : 010000110101 3.BP : 010101101010 Und schupdiwupp, da sind es acht Kombinationsmöglichkeiten : 000 , 001 , 010 , 011 , 100 , 101 , 110 , 111 - dezimal 0-7. Und so weiter... Quintessenz : Will man einen Screen mit 16 Farben, dann nehme man für Depth den Wert 4 (2^4 = 16). Für 32 muß man 5 Bitplanes wählen. A 2 : Diese Zahlen beziehen sich auf das in A 1 angesprochene Farbregister (0 - (2^Anzahl Bitplanes)-1). A 3 : Ein Screen ist ein Element, das relativ weit entfernt vom System ist. Weiter unten ist die sogenannte View-Struktur zu finden. "Auf ihr drauf" liegen ViewPorts, die man besser modifizieren kann als Views. "Auf denen" findet man nun RastPorts, welche wieder Teile von Screens sind, die wiederrum "unter" Windows liegen, welche den Inbegriff der Manipulationsfreundlichkeit darstellen. Nun sehen Standardviewports für Screens eine maximale horizontale Auflösung von 320 Pixeln und eine vertikale von 256 Pixeln vor. Um dies zu ändern, muß man das Feld ViewModes mit diversen Werten belegen. Diese sind in "Include:Graphics/View.I" (wird von Intuition.I mit einge- lesen) vordefiniert. So gibt es z.B. HIRES (erlaubt 640 Pixel horizontal) und LACE (aktiviert den sogenannten Interlace-Modus, welcher über einen Trick 512 vertikale Pixel erlaubt). A 4 : Es gibt zwei Arten von Screen : den CUSTOMSCREEN_f (wird in "include:Intuition/Intuition.i" definiert). Er ist sehr praktisch und wird auch meistens verwendet. Nachteil : sollten Sys-Requester (kennt jeder : "Disk is NOT a DOS Disk" , "Read/Write error", "No Disk present in", etc..) geöffnet werden, so wird der Workbenchscreen in den Vordergrund geschaltet, was verständlicherweise nicht besonders professionell wirkt. Die Alternative ist WBENCHSCREEN_f. Hier werden System-Requester auf dem Screen geöffnet. Traumhaft. Nachteil : man kriegt Probleme, wenn man in der Farbstruktur der Preferences rumpfuscht und wenn man aus Versehen den "alten" Workbenchscreen in den Vordergrund geschaltet hat und das eigene Programm öffnet plötzlich ein Fenster, dann erscheint dies auf dem "alten" Screen.... Also gut, hauen wir einen Screen auf. Program IntuitionTest (input , output); { Listing für den AMIGAGadget/Purity - Pascalkurs , Screen öffnen } {$I "Include:Intuition/Intuition.I" } VAR myscreen : ScreenPtr; PROCEDURE CloseDisplay; { Sollte ein Teil des Displays offen sein, dann wird er von } { dieser Routine geschlossen. } BEGIN IF myscreen<>NIL THEN CloseScreen (myscreen); END; PROCEDURE BreakProgram (reason : STRING); { Diese Routine schließt alles bisher geöffnete, druckt den } { Fehlergrund aus und bricht dann das Programm ab. } BEGIN CloseDisplay; WRITELN ('Program error : ',reason); Exit (42); END; PROCEDURE OpenDisplay; { Diese Routine erstellt ein Display. } CONST mynewscreen : NewScreen = (0,0,640,256,2,0,1,HIRES, CUSTOMSCREEN_f,NIL, "Unser erster Screen",NIL,NIL); BEGIN myscreen := OpenScreen (Adr(mynewscreen)); IF myscreen=NIL THEN BreakProgram ("Couldn't open Screen"); END; PROCEDURE WarteEinWenig; { Eine unelegante Routine, die nur dazu dient,das geöffnete } { Display zu betrachten. In späteren Programmen, wird sie } { durch eleganteren Stuff ersetzt. } VAR ww1 , ww2 : INTEGER; BEGIN FOR ww1:=1 TO 100 DO FOR ww2:=1 TO 2000 DO; END; BEGIN OpenDisplay; WarteEinWenig; CloseDisplay; END. Alles klar ?? Nun gut, wenden wir uns dem Window zu. Prinzipiell funktioniert die Sache wie mit dem Screen : NewWindowStruktur an OpenWindow übergeben, Zeiger auf WindowStruktur zurückerhalten. Also schnell der Blick auf die NewWindow-Struktur : NewWindow = record LeftEdge, TopEdge, Width, Height : Short; DetailPen, BlockPen : Byte; siehe NewScreen-Struktur IDCMPFlags : Integer; siehe B 1 Flags : Integer; siehe B 2 FirstGadget : Address; Zeiger auf das erste Gadget CheckMark : Address; unwichtig Title : String; Zeiger auf Titel des Windows Screen : Address; Zeiger auf den Screen BitMap : Address; Zeiger auf eigene BitMap MinWidth, siehe B 2 MinHeight, MaxWidth, MaxHeight : Short; WType : Short; siehe SType bei NewScreen end; B 1 : Der IDCMP-Port ist die Brücke zwischen dem Benutzer und Intuition. Hier wird dem Programmierer mitgeteilt, was der Anwender mit Intuition vorhat. Dies beinhaltet so Sachen wie Mausknopf gedrückt , Window geschlossen , etc. . Hiermit beschäftigen wir uns in der nächsten Folge im Kapitel Messages. B 2 : Hier werden einige grundlegende Eigenschaften des Windows festgelegt. Definiert in "Intuition.I" sind folgende : WINDOWSIZING : die Größe des Windows kann verändert werden. Maximum sowie Minimum der Windowgröße kann in den Feldern MinWidth,MinHeight,MaxWidth und MaxHeight festgelegt werden. WINDOWDRAG : man kann das Window durch die Gegend ziehen. WINDOWDEPTH : das Window bekommt Gadgets, mit denen man es hinter andere Windows schalten kann. WINDOWCLOSE : das Window erhält in der linken oberen Ecke ein Closegadget. Abfragen muß man es aber selber - wartet auf die nächste Folge. SIZEBRIGHT und SIZEBBOTTOM : treffen unwesentliche Aussagen über den Ort des WindowSizing-Gadgets SMART_REFRESH : der Amiga merkt sich in einem Speicherbereich, den er extra reserviert, Teile des Fensterinhalts, wenn dieses von anderen Fenstern überlagert wird. Normalerweise verwendet man diesen Modus. SIMPLE_REFRESH : Man erhält nur eine Message (nächste Folge !!!), wenn der Fensterinhalt wieder erneurt werden muß (da z.B. ein Filerequester Teile des Fensters überlagert hatte). Um den Vorgang an sich muß man sich aber selbst kümmern... SUPER_BITMAP : sehr speicherintensive Refreshalternative. Ein Speicherbereich im Amiga enthält den gesamten Fensterinhalt. Das dargestellte Window kann auch nur ein Ausschnitt aus dieser "SuperBitmap" sein.. OTHER_REFRESH : na ja... BACKDROP : ganz tolles Flag : das Window ist immer hinter allen anderen Windows des Screens REPORTMOUSE_f : Intuition speichert die aktuellen Mauskoordinaten in den Feldern MouseX und MouseY der Windowstruktur. GIMMEZEROZERO : Intuition betrachtet den Inhalt des Fensters getrennt von den äußeren Applikationen (Rahmen, Gadgets, etc.) BORDERLESS : das Fenster bekommt keinen Rahmen ACTIVATE : das Fenster wird nach dem Öffnen gleich aktiviert WINDOWACTIVE : das Fenster ist das gerade aktive INREQUEST : das Fenster ist im Requester-Modus MENUSTATE : die Menuleiste ist heruntergeklappt RMBTRAP : der rechte Mausknopf wird wie der linke behandelt + einige absolut unwichtige Genug der grauen Theorie - öffnet das Fenster !!! Program IntuitionTest (input , output); { Listing für den AMIGAGadget/Purity - Pascalkurs , } { Screen+Window öffnen } {$I "Include:Intuition/Intuition.I" } VAR myscreen : ScreenPtr; mywindow : WindowPtr; PROCEDURE CloseDisplay; { Sollte ein Teil des Displays offen sein, dann wird er von } { dieser Routine geschlossen. } BEGIN IF myscreen<>NIL THEN CloseScreen (myscreen); IF mywindow<>NIL THEN CloseWindow (mywindow); END; PROCEDURE BreakProgram (reason : STRING); { Diese Routine schließt alles bisher geöffnete, druckt den } { Fehlergrund aus und bricht dann das Programm ab. } BEGIN CloseDisplay; WRITELN ('Program error : ',reason); Exit (42); END; PROCEDURE OpenDisplay; { Diese Routine erstellt ein Display. } CONST mynewscreen : NewScreen = (0,0,640,256,2,0,1,HIRES, CUSTOMSCREEN_f,NIL, "Unser zweiter Screen",NIL,NIL); mynewwindow : NewWindow = (0,0,400,200,0,1,0, SMART_REFRESH+ACTIVATE+ WINDOWDRAG,NIL,NIL,"Unser erstes Fenster", NIL,NIL,0,0,0,0,CUSTOMSCREEN_f); BEGIN myscreen := OpenScreen (Adr(mynewscreen)); IF myscreen=NIL THEN BreakProgram ("Couldn't open Screen"); mynewwindow.Screen:=myscreen; mywindow := OpenWindow (Adr(mynewwindow)); IF mywindow=NIL THEN BreakProgram ("Couldn't open Window"); END; PROCEDURE WarteEinWenig; { Eine unelegante Routine, die nur dazu dient,das geöffnete } { Display zu betrachten. In späteren Programmen, wird sie } { durch eleganteren Stuff ersetzt. } VAR ww1 , ww2 : INTEGER; BEGIN FOR ww1:=1 TO 500 DO FOR ww2:=1 TO 2000 DO; END; BEGIN OpenDisplay; WarteEinWenig; CloseDisplay; END. So, das war's für heute. Probiert schön fleißig mal mit allen möglichen Window- und Screentypen herum. Sollte es Probleme oder Fragen geben, so wendet Euch mit einem Leserbrief an die Purity oder direkt an mich Andreas Neumann Auf dem Ruhbühl 151 W 7997 Immenstaad Tel.: 07545 / 3483 Übrigens : alle Routinen, die wir hier in dem Kurs entwickeln, können ruhig in eigene Programme übernommen werden. Ein Hinweis auf diesen tollen Kurs von mir wäre aber ganz nett. Viel Spaß und bis zur nächsten Purity, in dem es wieder heißt "END. gut , alles gut." © 14.09.1991 by Andreas Neumann für AmigaGadget von Nils Kassube und Purity von Steppenbrand und Diesel